package com.moo2u2.android.oaktononthego.timesheet;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;

import android.app.Activity;
import android.app.AlertDialog;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.res.Resources;
import android.database.Cursor;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentPagerAdapter;
import android.support.v4.content.CursorLoader;
import android.support.v4.content.Loader;
import android.support.v4.view.ViewPager;
import android.util.Log;
import android.view.ContextMenu;
import android.view.ContextMenu.ContextMenuInfo;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.view.Window;
import android.widget.AdapterView.AdapterContextMenuInfo;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.SimpleCursorAdapter;
import android.widget.TabHost;
import android.widget.TabWidget;
import android.widget.TextView;
import android.widget.Toast;

import com.moo2u2.android.oaktononthego.R;
import com.moo2u2.android.oaktononthego.fragment.CallbackListFragment;
import com.moo2u2.android.oaktononthego.timesheet.dao.TimesheetDbAdapter;
import com.moo2u2.android.oaktononthego.timesheet.dao.TimesheetEntryTable;
import com.moo2u2.android.oaktononthego.timesheet.dao.TimesheetTable;
import com.moo2u2.android.oaktononthego.util.Util;

/**
 * Mobile timesheet application based off Timezone
 * (https://timezone.oakton.com.au).
 * 
 * TODO reports TODO notes in new activity TODO settings: login, sync period
 * 
 * @author firewalker
 * 
 */
public class TimesheetActivity extends FragmentActivity {

	private static final int EDIT_ID = Menu.FIRST + 1;

	private static final int DELETE_ID = Menu.FIRST + 2;

	private static final int EDIT_PREFS = Menu.FIRST + 3;

	private static final int SUBMIT_TIMESHEET = 1234;

	private static final boolean SUBMITTED = true;

	private TabHost tabHost;

	private TabsAdapter tabsAdapter;

	private ViewPager viewPager;

	private TimesheetDbAdapter dbHelper;

	private Calendar currentWeek = Util.findEndOfWeek(Calendar.getInstance());

	private boolean currentSubmitted = false;

	private TextView weekDate;

	/** {@inheritDoc} */
	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);

		dbHelper = new TimesheetDbAdapter(this);

		final boolean customTitleSupported = requestWindowFeature(Window.FEATURE_CUSTOM_TITLE);
		setContentView(R.layout.timesheets_main);
		if (customTitleSupported)
			getWindow().setFeatureInt(Window.FEATURE_CUSTOM_TITLE,
					R.layout.window_title);

		initView();

		createTabs();

		if (savedInstanceState != null) {
			tabHost.setCurrentTabByTag(savedInstanceState.getString("tab"));
		} else {
			tabHost.setCurrentTab(0);
		}

		weekDate = (TextView) findViewById(R.id.week_date);
		changeWeek(0);

	}

	/** {@inheritDoc} */
	@Override
	protected void onSaveInstanceState(Bundle outState) {
		super.onSaveInstanceState(outState);
		outState.putString("tab", tabHost.getCurrentTabTag());
	}

	private void initView() {
		Button weekPrev = (Button) findViewById(R.id.week_prev);
		weekPrev.setOnClickListener(new OnClickListener() {
			public void onClick(View v) {
				changeWeek(-7);
			}
		});
		Button weekNext = (Button) findViewById(R.id.week_next);
		weekNext.setOnClickListener(new OnClickListener() {
			public void onClick(View v) {
				changeWeek(7);
			}
		});
	}

	private void createTabs() {
		Resources res = getResources();
		tabHost = (TabHost) findViewById(android.R.id.tabhost);
		tabHost.setup();

		viewPager = (ViewPager) findViewById(R.id.pager);

		tabsAdapter = new TabsAdapter(this, tabHost, viewPager);

		Bundle bundle = new Bundle();
		bundle.putInt("day", 0);
		tabsAdapter.addTab(
				tabHost.newTabSpec("monday").setIndicator("Monday",
						res.getDrawable(R.drawable.day_monday)),
				DayFragment.class, bundle);
		bundle = new Bundle();
		bundle.putInt("day", 1);
		tabsAdapter.addTab(
				tabHost.newTabSpec("tuesday").setIndicator("Tuesday",
						res.getDrawable(R.drawable.day_tuesday)),
				DayFragment.class, bundle);
		bundle = new Bundle();
		bundle.putInt("day", 2);
		tabsAdapter.addTab(
				tabHost.newTabSpec("wednesday").setIndicator("Wednesday",
						res.getDrawable(R.drawable.day_wednesday)),
				DayFragment.class, bundle);
		bundle = new Bundle();
		bundle.putInt("day", 3);
		tabsAdapter.addTab(
				tabHost.newTabSpec("thursday").setIndicator("Thursday",
						res.getDrawable(R.drawable.day_thursday)),
				DayFragment.class, bundle);
		bundle = new Bundle();
		bundle.putInt("day", 4);
		tabsAdapter.addTab(
				tabHost.newTabSpec("friday").setIndicator("Friday",
						res.getDrawable(R.drawable.day_friday)),
				DayFragment.class, bundle);
		bundle = new Bundle();
		bundle.putInt("day", 5);
		tabsAdapter.addTab(
				tabHost.newTabSpec("saturday").setIndicator("Saturday",
						res.getDrawable(R.drawable.day_saturday)),
				DayFragment.class, bundle);
		bundle = new Bundle();
		bundle.putInt("day", 6);
		tabsAdapter.addTab(
				tabHost.newTabSpec("sunday").setIndicator("Sunday",
						res.getDrawable(R.drawable.day_sunday)),
				DayFragment.class, bundle);
	}

	/** {@inheritDoc} */
	@Override
	public boolean onPrepareOptionsMenu(Menu menu) {
		menu.clear();
		if (!isCurrentSubmitted())
			menu.add(Menu.NONE, SUBMIT_TIMESHEET, Menu.NONE,
					R.string.submit_timesheet)
					.setIcon(android.R.drawable.ic_menu_save)
					.setAlphabeticShortcut('s');
		menu.add(Menu.NONE, EDIT_PREFS, Menu.NONE, "Edit Prefs")
				.setIcon(android.R.drawable.ic_menu_preferences)
				.setAlphabeticShortcut('e');
		return true;
	}

	/** {@inheritDoc} */
	@Override
	public boolean onOptionsItemSelected(MenuItem item) {
		switch (item.getItemId()) {
		case SUBMIT_TIMESHEET:
			submitTimesheet(this);
			return true;
		case EDIT_PREFS:
			startActivity(new Intent(this, TimesheetPreferences.class));
		default:
			return super.onOptionsItemSelected(item);
		}
	}

	private void submitTimesheet(Activity ctx) {
		// Check for 40 hours? Check for every day filled?
		// Call service
		// If successful:
		dbHelper.open();
		dbHelper.updateTimesheet(currentWeek.getTime(), SUBMITTED);
		dbHelper.close();

		changeWeek(0);

		Toast.makeText(ctx,
				"Timesheet for selected week succesfully submitted.",
				Toast.LENGTH_SHORT).show();
	}

	private void changeWeek(int days) {
		currentWeek.add(Calendar.DAY_OF_YEAR, days);
		weekDate.setText("Week ending: "
				+ new SimpleDateFormat(Util.DATE_FORMAT).format(currentWeek
						.getTime()));

		// TODO service call here
		SharedPreferences prefs = PreferenceManager
				.getDefaultSharedPreferences(this);
		// db set cache prefs.getString("weeksForward")
		// db set cache prefs.getString("weeksBack")
		// Save to DB

		// If not connected, use cached
		dbHelper.open();
		currentSubmitted = dbHelper.timesheetSubmitted(currentWeek.getTime());
		dbHelper.close();

		if (currentSubmitted) {
			((ImageView) findViewById(R.id.submitted_icon))
					.setImageDrawable(getResources().getDrawable(
							R.drawable.icon_submitted));
		} else {
			((ImageView) findViewById(R.id.submitted_icon))
					.setImageDrawable(getResources().getDrawable(
							R.drawable.icon_notsubmitted));
		}

		tabHost.setCurrentTab(0);
		if (tabsAdapter.getCurrentFragment() != null) {
			// Load new data
			tabsAdapter.getCurrentFragment().getLoaderManager()
					.restartLoader(0, null, tabsAdapter.getCurrentFragment());
		}

	}

	public Calendar getCurrentWeek() {
		return currentWeek;
	}

	public boolean isCurrentSubmitted() {
		return currentSubmitted;
	}

	/**
	 * From here
	 * http://developer.android.com/resources/samples/Support4Demos/src
	 * /com/example/android/supportv4/app/FragmentTabsPager.html
	 */
	public static class TabsAdapter extends FragmentPagerAdapter implements
			TabHost.OnTabChangeListener, ViewPager.OnPageChangeListener {
		private final Context mContext;

		private final TabHost mTabHost;

		private final ViewPager mViewPager;

		private final ArrayList<TabInfo> mTabs = new ArrayList<TabInfo>();

		// There has got to be a better way to do this
		private Fragment[] fragments = new Fragment[7];

		static final class TabInfo {
			// private final String tag;

			private final Class<?> clss;

			private final Bundle args;

			TabInfo(String _tag, Class<? extends Fragment> _class, Bundle _args) {
				// tag = _tag;
				clss = _class;
				args = _args;
			}
		}

		static class DummyTabFactory implements TabHost.TabContentFactory {
			private final Context mContext;

			public DummyTabFactory(Context context) {
				mContext = context;
			}

			/** {@inheritDoc} */
			@Override
			public View createTabContent(String tag) {
				View v = new View(mContext);
				v.setMinimumWidth(0);
				v.setMinimumHeight(0);
				return v;
			}
		}

		public TabsAdapter(FragmentActivity activity, TabHost tabHost,
				ViewPager pager) {
			super(activity.getSupportFragmentManager());
			mContext = activity;
			mTabHost = tabHost;
			mViewPager = pager;
			mTabHost.setOnTabChangedListener(this);
			mViewPager.setAdapter(this);
			mViewPager.setOnPageChangeListener(this);
		}

		public void addTab(TabHost.TabSpec tabSpec,
				Class<? extends Fragment> clss, Bundle args) {
			tabSpec.setContent(new DummyTabFactory(mContext));
			String tag = tabSpec.getTag();

			TabInfo info = new TabInfo(tag, clss, args);
			mTabs.add(info);
			mTabHost.addTab(tabSpec);
			notifyDataSetChanged();
		}

		/** {@inheritDoc} */
		@Override
		public int getCount() {
			return mTabs.size();
		}

		/** {@inheritDoc} */
		@Override
		public Fragment getItem(int position) {
			TabInfo info = mTabs.get(position);
			fragments[position] = Fragment.instantiate(mContext,
					info.clss.getName(), info.args);
			return fragments[position];
		}

		public DayFragment getCurrentFragment() {
			return (DayFragment) fragments[mTabHost.getCurrentTab()];
		}

		/** {@inheritDoc} */
		@Override
		public void onTabChanged(String tabId) {
			int position = mTabHost.getCurrentTab();
			Log.i(this.getClass().getSimpleName(), "Current tab: " + position);
			mViewPager.setCurrentItem(position);
		}

		/** {@inheritDoc} */
		@Override
		public void onPageScrolled(int position, float positionOffset,
				int positionOffsetPixels) {
			notifyDataSetChanged();
		}

		/** {@inheritDoc} */
		@Override
		public void onPageSelected(int position) {
			notifyDataSetChanged();
			TabWidget widget = mTabHost.getTabWidget();
			int oldFocusability = widget.getDescendantFocusability();
			widget.setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS);
			mTabHost.setCurrentTab(position);
			widget.setDescendantFocusability(oldFocusability);
		}

		/** {@inheritDoc} */
		@Override
		public void onPageScrollStateChanged(int state) {
		}
	}

	public static class DayFragment extends CallbackListFragment {

		private static final String[] TIMESHEET_ROW_PROJECTION = new String[] {
				TimesheetEntryTable.KEY_ROWID,
				TimesheetEntryTable.KEY_TIMESHEET, TimesheetEntryTable.KEY_DAY,
				TimesheetEntryTable.KEY_TYPE, TimesheetEntryTable.KEY_SUBTYPE,
				TimesheetEntryTable.KEY_HOURS };

		private static final int NEW_ENTRY = Menu.FIRST;

		private static final int CLEAR_DAY = Menu.FIRST + 1;

		private int day = 0;

		private SimpleCursorAdapter entries;

		/**
		 * When creating, retrieve this instance's number from its arguments.
		 */
		@Override
		public void onCreate(Bundle savedInstanceState) {
			super.onCreate(savedInstanceState);
			day = getArguments() != null ? getArguments().getInt("day") : 0;
		}

		/** {@inheritDoc} */
		@Override
		public void onActivityCreated(Bundle savedInstanceState) {
			super.onActivityCreated(savedInstanceState);

			setEmptyText(getText(R.string.no_timesheet_entries));
			setHasOptionsMenu(true);

			entries = new TimesheetAdapter(getActivity(),
					R.layout.timesheet_row, null, new String[] {
							TimesheetEntryTable.KEY_TYPE,
							TimesheetEntryTable.KEY_SUBTYPE,
							TimesheetEntryTable.KEY_HOURS }, new int[] {
							R.id.type, R.id.subtype, R.id.hours });
			setListAdapter(entries);

			setListShown(false);
			getLoaderManager().initLoader(0, null, this);
			registerForContextMenu(getListView());

			if (((TimesheetActivity) getActivity()).isCurrentSubmitted()) {
				((TimesheetAdapter) getListAdapter()).setEnabled(false);
			} else {
				((TimesheetAdapter) getListAdapter()).setEnabled(true);
			}
		}

		@Override
		public void onCreateContextMenu(ContextMenu menu, View v,
				ContextMenuInfo menuInfo) {
			super.onCreateContextMenu(menu, v, menuInfo);
			if (!((TimesheetActivity) getActivity()).isCurrentSubmitted()) {
				menu.add(0, EDIT_ID, 0, R.string.edit);
				menu.add(0, DELETE_ID, 0, R.string.delete);
			}
		}

		@Override
		public boolean onContextItemSelected(MenuItem item) {
			AdapterContextMenuInfo info = (AdapterContextMenuInfo) item
					.getMenuInfo();
			TimesheetActivity activity = (TimesheetActivity) getActivity();
			TimesheetDbAdapter dbHelper;
			switch (item.getItemId()) {
			case EDIT_ID:
				Log.i(this.getClass().getSimpleName(), "Editing entry...");
				dbHelper = new TimesheetDbAdapter(activity);
				dbHelper.open();
				Cursor entryDetails = dbHelper.fetchTimesheetEntry(info.id);
				TimesheetEntryPrompt prompt = new TimesheetEntryPrompt(
						activity, this, activity.getCurrentWeek(), getDay(),
						entryDetails);
				AlertDialog dialog = prompt.create();
				prompt.setDialog(dialog); // ugly hack
				prompt.show();
				dbHelper.close();
				getLoaderManager().restartLoader(0, null, this);
				return true;
			case DELETE_ID:
				Log.i(this.getClass().getSimpleName(), "Deleting entry...");
				dbHelper = new TimesheetDbAdapter(activity);
				dbHelper.open();
				dbHelper.deleteTimesheetEntry(info.id);
				dbHelper.close();
				getLoaderManager().restartLoader(0, null, this);
				return true;
			default:
				return super.onOptionsItemSelected(item);
			}
		}

		/** {@inheritDoc} */
		@Override
		public void onPrepareOptionsMenu(Menu menu) {
			if (!((TimesheetActivity) getActivity()).isCurrentSubmitted()) {
				menu.add(Menu.NONE, NEW_ENTRY, 0, R.string.new_entry).setIcon(
						android.R.drawable.ic_menu_add);
				menu.add(Menu.NONE, CLEAR_DAY, 0, R.string.clear_day).setIcon(
						android.R.drawable.ic_menu_delete);
			}
		}

		/** {@inheritDoc} */
		@Override
		public boolean onOptionsItemSelected(MenuItem item) {
			TimesheetActivity activity = (TimesheetActivity) getActivity();
			if (!activity.isCurrentSubmitted()) {
				switch (item.getItemId()) {
				case NEW_ENTRY:
					Log.i(this.getClass().getSimpleName(), "Adding entry");
					TimesheetEntryPrompt prompt = new TimesheetEntryPrompt(
							activity, this, activity.getCurrentWeek(),
							getDay(), null);
					AlertDialog dialog = prompt.create();
					prompt.setDialog(dialog); // ugly hack
					dialog.show();
					return true;
				case CLEAR_DAY:
					TimesheetDbAdapter dbHelper = new TimesheetDbAdapter(
							activity);
					dbHelper.open();
					dbHelper.deleteTimesheetsForWeek(activity.getCurrentWeek()
							.getTime());
					dbHelper.close();
					getLoaderManager().restartLoader(0, null, this);
					return true;
				default:
					return super.onOptionsItemSelected(item);
				}
			}
			return super.onOptionsItemSelected(item);
		}

		/** {@inheritDoc} */
		@Override
		public void onListItemClick(ListView l, View v, int position, long id) {
			Log.i(this.getClass().getSimpleName(), "Item clicked: " + id);
		}

		/** {@inheritDoc} */
		@Override
		public Loader<Cursor> onCreateLoader(int id, Bundle args) {
			CursorLoader cl = new CursorLoader(getActivity(),
					TimesheetEntryTable.CONTENT_URI, TIMESHEET_ROW_PROJECTION,
					TimesheetEntryTable.KEY_TIMESHEET + " = (SELECT "
							+ TimesheetTable.KEY_ROWID + " FROM "
							+ TimesheetTable.TIMESHEET_TABLE + " WHERE "
							+ TimesheetTable.KEY_ENDDATE + " = ?) AND "
							+ TimesheetEntryTable.KEY_DAY + " = ?",
					new String[] {
							new SimpleDateFormat(
									TimesheetDbAdapter.DB_DATE_FORMAT)
									.format(((TimesheetActivity) getActivity())
											.getCurrentWeek().getTime()),
							String.valueOf(day) }, null);
			cl.setUpdateThrottle(2000); // update at most every 2 seconds.
			return cl;
		}

		/** {@inheritDoc} */
		@Override
		public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
			entries.changeCursor(data);

			if (isResumed()) {
				setListShown(true);
				if (((TimesheetActivity) getActivity()).isCurrentSubmitted()) {
					((TimesheetAdapter) getListAdapter()).setEnabled(false);
				} else {
					((TimesheetAdapter) getListAdapter()).setEnabled(true);
				}
			} else {
				setListShownNoAnimation(true);
			}
		}

		/** {@inheritDoc} */
		@Override
		public void onLoaderReset(Loader<Cursor> loader) {
			entries.changeCursor(null);
		}

		public void setDay(int day) {
			this.day = day;
		}

		public int getDay() {
			return day;
		}
	}

}